package com.xuecheng.search.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.xuecheng.commons.enums.ErrorCode;
import com.xuecheng.commons.model.dto.CoursePubIndexDto;
import com.xuecheng.commons.model.dto.PageRequest;
import com.xuecheng.commons.model.vo.*;
import com.xuecheng.commons.utils.BeanHelper;
import com.xuecheng.content.api.ContentClient;
import com.xuecheng.search.domain.CoursePubIndex;
import com.xuecheng.search.service.SearchService;
import com.xuecheng.web.exception.BusinessException;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.zip.CheckedOutputStream;

@Service
public class SearchServiceImpl implements SearchService {
    @Autowired
    private ContentClient contentClient;
    @Autowired
    private RestHighLevelClient client;
    //课程同步
    @Override
    public void CoursePubsyncToEs(Long coursePubId) throws IOException {
        //1.根据课程发布id查询对象
        ResponseResult<CoursePubVo> responseResult = contentClient.findById(coursePubId);
        if ((responseResult.getCode()!=0)) {
            throw new BusinessException(ErrorCode.NOTFOUND);
        }
        CoursePubVo coursePubVo = responseResult.getData();
        //转为索引实体类
        CoursePubIndex coursePubIndex = BeanHelper.copyProperties(coursePubVo, CoursePubIndex.class);
        coursePubIndex.setCourse_id(coursePubVo.getCourseId());
        coursePubIndex.setCompany_id(coursePubVo.getCompanyId());
        coursePubIndex.setCompany_name(coursePubVo.getCompanyName());
        coursePubIndex.setCreate_date(new Date());
        coursePubIndex.setIs_latest(coursePubVo.getIsLatest());
        coursePubIndex.setIs_pub(coursePubVo.getIsPub());
        coursePubIndex.setPrice(coursePubVo.getPrice().floatValue()*100);

        //3.创建request
        IndexRequest request = new IndexRequest("course").id(coursePubId.toString());
        //4.准备DSL
        request.source(JSON.toJSONString(coursePubIndex), XContentType.JSON);
        //5.发送请求
        client.index(request, RequestOptions.DEFAULT);



    }

    @Override
    public ResponseResult getCourse(PageRequest pageParam, CoursePubIndexDto dto) throws IOException{
        //1.创建查询request
        SearchRequest request = new SearchRequest("course");
        //2.准备DSL
        buildDSL(pageParam,dto,request);
        //3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //4.解析并返回请求
        return getResponseResult(response);

    }

    private void buildDSL(PageRequest pageParam, CoursePubIndexDto dto, SearchRequest request) {
        //2-1.
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if (StrUtil.isEmpty(dto.getKeyword())) {
            boolQuery.must(QueryBuilders.matchQuery("all",dto.getKeyword()));
        }
        else {
            boolQuery.must(QueryBuilders.matchAllQuery());
        }
        //一级分类
        if (StrUtil.isNotEmpty(dto.getMt())) {
            boolQuery.filter(QueryBuilders.termQuery("mt", dto.getMt()));

        }
        //二级分类
        if (StrUtil.isNotEmpty(dto.getSt())) {
            boolQuery.filter(QueryBuilders.termQuery("st", dto.getSt()));

        }
        //课程等级
        if (StrUtil.isNotEmpty(dto.getGrade())) {
            boolQuery.filter(QueryBuilders.termQuery("grade", dto.getGrade()));
        }
        request.source().query(boolQuery);
        //2-2 分页
        Integer pageNo = pageParam.getPageNo();
        Integer pageSize = pageParam.getPageSize();

        Integer index = (pageNo - 1) * pageSize;
        request.source().from(index).size(pageSize);
        //2-3高亮
        request.source().highlighter(new HighlightBuilder()
                .field("name")
                .preTags("<font color=red>")
                .postTags("</font>")
                .requireFieldMatch(false));

    }

    //解析并返回结果
    public ResponseResult getResponseResult(SearchResponse response){
        //4.1获取命中结果
        SearchHits hits = response.getHits();
        //4-2.获取命中结果
        long total = hits.getTotalHits().value;
        //4-3.取出结果数组
        SearchHit[] hitsArray = hits.getHits();
        List<CoursePubIndexVo> voList=new ArrayList<>();
        //4-4.判断
        if (ArrayUtil.isNotEmpty(hitsArray)) {
            //遍历
            for (SearchHit hit : hitsArray) {
                //获取原始JSON
                String json = hit.getSourceAsString();
                CoursePubIndexVo vo = JSON.parseObject(json, CoursePubIndexVo.class);
                vo.setIndexId(vo.getCourseId());
                // 5. 处理高亮
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                // 5-1 map非空判断
                if (CollUtil.isNotEmpty(highlightFields)) {
                    HighlightField nameArray = highlightFields.get("name");
                    // 5-2 对name数组非空判断
                    if (ArrayUtil.isNotEmpty(nameArray)) {
                        String name = nameArray.getFragments()[0].toString();
                        // 5-3 将高亮设置到vo
                        vo.setName(name);
                    }
                }
                voList.add(vo);

            }
        }


        return PageResponseResult.okResult(total,voList);
    }
    //根据id查询课程
    @Override
    public ResponseResult getPubCourseById(String id) throws IOException {
        //1.创建请求
        GetRequest request = new GetRequest("course").id(String.valueOf(id));
        //2.准备DSL -已完成
        //3.发送请求
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        //4.解析结果
        String json = response.getSourceAsString();
        CoursePubIndexVo vo = JSON.parseObject(json, CoursePubIndexVo.class);

        return ResponseResult.okResult(vo);
    }

    @Override
    public void removeDocument(Long coursePubId) throws IOException {
        //1.创建删除请求
        DeleteRequest request = new DeleteRequest();
        //2.准备DSL
        request.index("course").id(coursePubId.toString());
        //3.发送请求
        client.delete(request, RequestOptions.DEFAULT);
        //4.返回结果
    }
}


